﻿#include "FITKGraphObjectConnectorAssignment.h"

// VTK
#include <vtkUnstructuredGrid.h>
#include <vtkPoints.h>
#include <vtkPointSource.h>
#include <vtkStringArray.h>
#include <vtkPointData.h>
#include <vtkSmartPointer.h>
#include <vtkDataSetMapper.h>
#include <vtkCellType.h>
#include <vtkProperty.h>
#include <vtkProperty2D.h>
#include <vtkTextProperty.h>
#include <vtkLabelHierarchy.h>
#include <vtkPointSetToLabelHierarchy.h>
#include <vtkSelectVisiblePoints.h>
#include <vtkRenderer.h>

// Render
#include "FITK_Component/FITKRenderWindowVTK/FITKGraphRender.h"

// Graph
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor2D.h"
#include "FITKGraphObjectCoordinateInternal.h"
#include "FITKGraphCommons.h"

// Mapper and strategy
#include <vtkLabelPlacementMapper.h>
#include <vtkFreeTypeLabelRenderStrategy.h>
#include "FITK_Interface/FITKVTKAlgorithm/FITKPolyPlacementMapper.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKPolyRenderStrategy.h"

// Global data
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"

// Data
#include "FITK_Component/FITKAbaqusData/FITKDataCase.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaConnectorAssignment.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaWire.h"
#include "FITK_Interface/FITKInterfaceModel/FITKModelSet.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAssembly.h"
#include "FITK_Interface/FITKInterfaceModel/FITKCoordinateSystem.h"

namespace Exchange
{
    FITKGraphObjectConnectorAssignment::FITKGraphObjectConnectorAssignment(AbaqusData::FITKDataCase* caseData, Interface::FITKAbaConnectorAssignment* connector)
        : FITKGraphObjectLineBase(caseData, connector)
    {
        if (!connector || !caseData)
        {
            return;
        }

        // Initialize.
        init();

        // Generate the line, glyph and text grid.
        bool flag = generatePolyData(connector);
        if (!flag)
        {
            return;
        }

        // Generate the wire actor.
        generateGraph();

        // Update the visibility.
        updateVisibility();

        // Set the layer need to be rendered.
        setRenderLayer(0, 1);

        // Save the graph information.
        m_graphInfo.Type = OtherGraph;

        // Save if the bounds are fixed or dynamic.
        m_hasFixedBounds = true;
    }

    FITKGraphObjectConnectorAssignment::~FITKGraphObjectConnectorAssignment()
    {
        // Delete data.
        //@{
        deleteVtkObj(m_pointsStart);
        deleteVtkObj(m_ugridStart);

        deleteVtkObj(m_pointsEnd);
        deleteVtkObj(m_ugridEnd);

        deleteVtkObj(m_pointsLine);
        deleteVtkObj(m_ugridLine);

        deleteVtkObj(m_textProperty);
        deleteVtkObj(m_textArray);
        deleteVtkObj(m_pointsLabel);
        deleteVtkObj(m_ugridLabel);
        //@}

        // Delete source and strategy.
        deleteVtkObj(m_pointSourceStart);
        deleteVtkObj(m_strategyEnd);

        // Delete the hierarchy.
        deleteVtkObj(m_labelHieEnd);
        deleteVtkObj(m_labelHieText);

        // Delete the filter.
        deleteVtkObj(m_visiblePtEnd);
        deleteVtkObj(m_visiblePtText);
    }

    void FITKGraphObjectConnectorAssignment::init()
    {
        // Create the grid data for start points.
        m_ugridStart = vtkUnstructuredGrid::New();
        m_pointsStart = vtkPoints::New();
        m_ugridStart->SetPoints(m_pointsStart);

        // Create the grid data for end points.
        m_ugridEnd = vtkUnstructuredGrid::New();
        m_pointsEnd = vtkPoints::New();
        m_ugridEnd->SetPoints(m_pointsEnd);

        // Create the grid data for lines.
        m_ugridLine = vtkUnstructuredGrid::New();
        m_pointsLine = vtkPoints::New();
        m_ugridLine->SetPoints(m_pointsLine);

        // Create the grid data for text label(s).
        m_ugridLabel = vtkUnstructuredGrid::New();
        m_pointsLabel = vtkPoints::New();
        m_ugridLabel->SetPoints(m_pointsLabel);
        m_textArray = vtkStringArray::New();
        m_textArray->SetName("_label_");
        m_textArray->SetNumberOfComponents(1);
        m_ugridLabel->GetPointData()->AddArray(m_textArray);

        // Create the text property.
        m_textProperty = vtkTextProperty::New();
        m_textProperty->SetBold(false);
        m_textProperty->SetFontSize(m_fontSize);

        // Get the lines' color( also the text color ).
        double colorLine3[3]{ 0., 0., 0. };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_connLineColor, colorLine3);
        m_textProperty->SetColor(colorLine3);

        // Create the visible points filter.
        //@{
        m_visiblePtEnd = vtkSelectVisiblePoints::New();
        m_visiblePtEnd->SetInputData(m_ugridEnd);

        m_visiblePtText = vtkSelectVisiblePoints::New();
        m_visiblePtText->SetInputData(m_ugridLabel);
        //@}

        // Point source for start points.
        //@{
        m_pointSourceStart = vtkPointSource::New();
        m_pointSourceStart->SetNumberOfPoints(1);
        //@}

        // Label hierarchy for end points.
        //@{
        m_labelHieEnd = vtkPointSetToLabelHierarchy::New();
        m_labelHieEnd->SetInputConnection(m_visiblePtEnd->GetOutputPort());
        m_labelHieEnd->SetTargetLabelCount(1);
        m_labelHieEnd->SetMaximumDepth(15);
        m_labelHieEnd->Update();
        //@}

        // Label hierarchy for label(s).
        //@{
        m_labelHieText = vtkPointSetToLabelHierarchy::New();
        m_labelHieText->SetInputConnection(m_visiblePtText->GetOutputPort());
        m_labelHieText->SetTargetLabelCount(1);
        m_labelHieText->SetMaximumDepth(15);
        m_labelHieText->SetLabelArrayName(m_textArray->GetName());
        m_labelHieText->SetTextProperty(m_textProperty);
        m_labelHieText->Update();
        //@}

        // Initialize coordinate objects.
        //@{
        m_coordGraphObj_1 = new FITKGraphObjectCoordinateInternal(m_caseData);
        m_coordGraphObj_1->setCustomPositions(m_ugridStart);
        m_coordGraphObj_1->setColor(FITKGraphCommons::s_connCsysColor);
        m_addinGraphObjList.push_back(m_coordGraphObj_1);

        m_coordGraphObj_2 = new FITKGraphObjectCoordinateInternal(m_caseData);
        m_coordGraphObj_2->setCustomPositions(m_ugridEnd);
        m_coordGraphObj_2->setColor(FITKGraphCommons::s_connCsysColor);
        m_addinGraphObjList.push_back(m_coordGraphObj_2);
        //@}
    }

    void FITKGraphObjectConnectorAssignment::initActors()
    {
        // Get the actor's color.
        //@{
        // Get the start points' color.
        double colorStart3[3]{ 0., 0., 0. };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_connStartPtColor, colorStart3);

        // Get the end points' color.
        double colorEnd3[3]{ 0., 0., 0. };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_connEndPtColor, colorEnd3);

        // Get the lines' color( also the text color ).
        double colorLine3[3]{ 0., 0., 0. };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_connLineColor, colorLine3);
        //@}

        // Generate the start point actor.
        m_fActorStart = FITKGraphActor::New();
        m_fActorStart->setActorType(ActorType::OtherActor);
        m_fActorStart->setGraphObject(this);
        m_fActorStart->SetPickable(false);
        m_fActorStart->SetVisibility(true);
        addActor(m_fActorStart);

        // Generate the end point actor.
        m_fActorEnd = FITKGraphActor2D::New();
        m_fActorEnd->setActorType(ActorType2D::GlyphActor);
        m_fActorEnd->setGraphObject(this);
        m_fActorEnd->SetPickable(false);
        m_fActorEnd->SetVisibility(true);
        addActor(m_fActorEnd);

        // Generate the line actor.
        m_fActorLine = FITKGraphActor::New();
        m_fActorLine->setGraphObject(this);
        m_fActorLine->SetPickable(false);
        m_fActorLine->SetVisibility(true);
        addActor(m_fActorLine);

        // Generate the text actor.
        m_fActorLabel = FITKGraphActor2D::New();
        m_fActorLabel->setActorType(ActorType2D::TextActor);
        m_fActorLabel->setGraphObject(this);
        m_fActorLabel->SetPickable(false);
        m_fActorLabel->SetVisibility(true);
        addActor(m_fActorLabel);

        // Generate stategy for shapes.
        //@{
        m_strategyEnd = FITKPolyRenderStrategy::New();
        m_strategyEnd->SetPixelSize(m_glyphSize);
        m_strategyEnd->SetSourceType(SourceType::Triangle, true);
        m_strategyEnd->SetColor(colorEnd3);
        //@}
    }

    void FITKGraphObjectConnectorAssignment::update(bool forceUpdate)
    {
        Interface::FITKAbaConnectorAssignment* connector = dynamic_cast<Interface::FITKAbaConnectorAssignment*>(_dataObj);
        if (!connector)
        {
            return;
        }

        QString typeName;

        bool needUpdateGrid = false;
        bool needUpdateText = false;
        bool needUpdateCsys = false;

        if (forceUpdate)
        {
            needUpdateGrid = true;
            needUpdateText = true;
            needUpdateCsys = true;
        }
        else
        {
            // Check type name.
            typeName = connector->getSectionType();
            needUpdateText = m_typeName != typeName;

            // Get the assembly.
            Interface::FITKAbaAssembly* assembly = m_caseData->getAssembly();
            if (!assembly)
            {
                return;
            }

            // Get the wire manager.
            Interface::FITKAbaWireManager* wireMgr = assembly->getWireManager();
            if (!wireMgr)
            {
                return;
            }

            // Get the connector type name.
            QString connTypeName = connector->getSectionType();

            // Get the set which parent model is an assembly.
            Interface::FITKModelSet* connSet = getConnectorSet(connector);
            if (!connSet)
            {
                return;
            }

            // Get the assembly elements.
            const QList<int> & members = connSet->getAbsoluteMember();
            if (m_lastLinesInfo.count() == members.count())
            {
                for (int i = 0; i < members.count(); i++)
                {
                    const int & member = members[i];

                    // Get the line data.
                    Interface::FITKAbaAssEle3D2* line = wireMgr->getElementByID(member);
                    if (!line)
                    {
                        continue;
                    }

                    // Get the ids of the model and node.
                    _LineInfo info;
                    line->getNode1(info._ModelId_1, info._NodeId_1);
                    line->getNode2(info._ModelId_2, info._NodeId_2);

                    _LineInfo & savedInfo = m_lastLinesInfo[i];
                    if (savedInfo._ModelId_1 != info._ModelId_1 || savedInfo._ModelId_2 != info._ModelId_2 ||
                        savedInfo._NodeId_1 != info._NodeId_1 || savedInfo._NodeId_2 != info._NodeId_2)
                    {
                        needUpdateGrid = true;
                        needUpdateCsys = true;
                        break;
                    }
                }
            }
            else
            {
                needUpdateGrid = true;
                needUpdateCsys = true;
            }
        }

        // Check the coordinate system.
        if (!needUpdateCsys && !needUpdateGrid)
        {
            int csysId_1 = connector->getCsysId1();
            int csysId_2 = connector->getCsysId2();

            needUpdateCsys |= (csysId_1 != m_csysId_1);
            needUpdateCsys |= (csysId_2 != m_csysId_2);
        }

        // Generate the poly data.
        if (needUpdateGrid)
        {
            // Clear data first.
            clearData();

            // Re-generate grid data.
            generatePolyData(connector);
        }
        else
        {
            // Re-generate the text only.
            if (needUpdateText)
            {
                int nText = m_textArray->GetNumberOfValues();
                resetVtkObj(m_textArray);

                for (int i = 0; i < nText; i++)
                {
                    m_textArray->InsertNextValue(QStringToCharA(typeName));
                }
            }

            // Re-generate the coordinate system only.
            if (needUpdateCsys)
            {
                // Clear data first.
                clearCsysData();

                generateCsys();
            }
        }

        // Update the whole visibility at last.
        updateVisibility();
    }

    void FITKGraphObjectConnectorAssignment::updateVisibility()
    {
        // Generate the coordinate graph.
        Interface::FITKAbaConnectorAssignment* connector = dynamic_cast<Interface::FITKAbaConnectorAssignment*>(_dataObj);
        if (!connector)
        {
            return;
        }

        int csysId_1 = connector->getCsysId1();
        int csysId_2 = connector->getCsysId2();

        // Try to get the coordinate object 1.
        Interface::FITKCoordinateSystem* coord_1 = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKCoordinateSystem>(csysId_1);
        if (m_coordGraphObj_1)
        {
            m_coordGraphObj_1->setVisible(coord_1 != nullptr);
        }

        // Try to get the coordinate object 2.
        Interface::FITKCoordinateSystem* coord_2 = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKCoordinateSystem>(csysId_2);
        if (m_coordGraphObj_2)
        {
            m_coordGraphObj_2->setVisible(coord_2 != nullptr);
        }

        // Show or hide full graph object.
        FITKGraphObject3D::updateVisibility();
    }

    void FITKGraphObjectConnectorAssignment::highlight(QColor color)
    {
        // This graph object can be highlighted in multiple colors,
        // but the given color will only change the highlight color
        // of the glyph.( Except lines )

        // If the object is invisible, then return.
        if (!getDataVisibility())
        {
            return;
        }

        // Get the highlight color.
        double color3[3]{ 0., 0., 0. };
        if (color.isValid())
        {
            FITKGraphCommons::QColorToDouble3(color, color3);
        }
        else
        {
            FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_connHighlightColor, color3);
        }

        // Change glyph actors' color.
        if (m_strategyEnd)
        {
            m_strategyEnd->SetColor(color3);
        }

        // Set the text color.
        if (m_textProperty)
        {
            m_textProperty->SetColor(color3);
        }

        // Get the lines' highlight color.
        double colorLine3[3]{ 0., 0., 0. };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_connLineHighlightColor, colorLine3);

        // Change line actor's color.
        if (m_fActorLine)
        {
            m_fActorLine->GetProperty()->SetColor(colorLine3);
        }

        // Disable the visible points.
        enableVisiblePoints(false);

        // For the coordinates.
        if (m_coordGraphObj_1)
        {
            m_coordGraphObj_1->highlight(FITKGraphCommons::s_connHighlightColor);
        }

        if (m_coordGraphObj_2)
        {
            m_coordGraphObj_2->highlight(FITKGraphCommons::s_connHighlightColor);
        }

        FITKGraphObject3D::highlight();
    }

    void FITKGraphObjectConnectorAssignment::disHighlight()
    {
        // Get the actor's color.
        //@{
        // Get the end points' color.
        double colorEnd3[3]{ 0., 0., 0. };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_connEndPtColor, colorEnd3);

        // Get the lines' color( also the text color ).
        double colorLine3[3]{ 0., 0., 0. };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_connLineColor, colorLine3);
        //@}

        // Reset the actors' color.
        //@{
        // Change glyph actors' color.
        if (m_strategyEnd)
        {
            m_strategyEnd->SetColor(colorEnd3);
        }

        // Change line actor's color.
        if (m_fActorLine)
        {
            m_fActorLine->GetProperty()->SetColor(colorLine3);
        }

        // Set the text color.
        if (m_textProperty)
        {
            m_textProperty->SetColor(colorLine3);
        }
        //@}

        // Enable the visible points.
        enableVisiblePoints(true);

        // For the coordinates.
        if (m_coordGraphObj_1)
        {
            m_coordGraphObj_1->disHighlight();
        }

        if (m_coordGraphObj_2)
        {
            m_coordGraphObj_2->disHighlight();
        }

        FITKGraphObject3D::disHighlight();
    }

    void FITKGraphObjectConnectorAssignment::setVisible(bool visibility)
    {
        // Set the visibility for all actors.
        if (m_fActorStart)
        {
            m_fActorStart->SetVisibility(visibility);
        }

        if (m_fActorEnd)
        {
            m_fActorEnd->SetVisibility(visibility);
        }

        if (m_fActorLine)
        {
            m_fActorLine->SetVisibility(visibility);
        }

        if (m_fActorLabel)
        {
            m_fActorLabel->SetVisibility(visibility);
        }

        // For the coordinates.
        //@{
        // Try to get the coordinate object 1.
        Interface::FITKCoordinateSystem* coord_1 = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKCoordinateSystem>(m_csysId_1);
        if (m_coordGraphObj_1)
        {
            m_coordGraphObj_1->setVisible(visibility && coord_1 != nullptr);
        }

        Interface::FITKCoordinateSystem* coord_2 = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKCoordinateSystem>(m_csysId_2);
        if (m_coordGraphObj_2)
        {
            m_coordGraphObj_2->setVisible(visibility && coord_2 != nullptr);
        }
        //@}
    }

    void FITKGraphObjectConnectorAssignment::setFITKRender(Comp::FITKGraphRender* render)
    {
        if (!render)
        {
            return;
        }

        vtkRenderer* renderer = render->getRenderer();
        if (!renderer)
        {
            return;
        }

        // Set the renderer for check if the points are visible.
        if (m_visiblePtEnd)
        {
            m_visiblePtEnd->SetRenderer(renderer);
        }

        if (m_visiblePtText)
        {
            m_visiblePtText->SetRenderer(renderer);
        }

        if (m_strategyEnd)
        {
            m_strategyEnd->SetRenderer(renderer);
        }

        // Set renderer for the coordinate objects.
        if (m_coordGraphObj_1)
        {
            m_coordGraphObj_1->setFITKRender(render);
        }

        if (m_coordGraphObj_2)
        {
            m_coordGraphObj_2->setFITKRender(render);
        }

        // Save the render.
        this->Superclass::setFITKRender(render);
    }

    Interface::FITKModelSet* FITKGraphObjectConnectorAssignment::getConnectorSet(Interface::FITKAbaConnectorAssignment* connector)
    {
        if (!connector)
        {
            return nullptr;
        }

        // Get the set id.
        int setId = connector->getModelID();

        // Get the set data.
        Interface::FITKModelSet* set = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKModelSet>(setId);
        if (!set)
        {
            return nullptr;
        }

        // Get element set(s).
        QList<Interface::FITKModelSet*> sets;
        set->getAbsoluteSet(sets, Interface::FITKModelEnum::FITKModelSetType::FMSElem);

        // Get the set which parent model is an assembly.
        Interface::FITKModelSet* connSet{ nullptr };
        for (Interface::FITKModelSet* s : sets)
        {
            if (!s)
            {
                continue;
            }

            Interface::FITKAbaAssembly* assembly = s->getAbstractModelAs<Interface::FITKAbaAssembly>();
            if (assembly)
            {
                connSet = s;
                break;
            }
        }

        return connSet;
    }

    bool FITKGraphObjectConnectorAssignment::generatePolyData(Interface::FITKAbaConnectorAssignment* connector)
    {
        // Get the assembly.
        Interface::FITKAbaAssembly* assembly = m_caseData->getAssembly();
        if (!assembly)
        {
            return false;
        }

        // Get the wire manager.
        Interface::FITKAbaWireManager* wireMgr = assembly->getWireManager();
        if (!wireMgr)
        {
            return false;
        }

        // Get the connector type name.
        QString connTypeName = connector->getSectionType();

        // Get the set which parent model is an assembly.
        Interface::FITKModelSet* connSet = getConnectorSet(connector);
        if (!connSet)
        {
            return false;
        }

        // Get the assembly elements.
        const QList<int> & members = connSet->getAbsoluteMember();
        for (const int & member : members)
        {
            // Get the line data.
            Interface::FITKAbaAssEle3D2* line = wireMgr->getElementByID(member);
            if (!line)
            {
                continue;
            }

            // Get the coordinate.
            double coord_1[3]{ 0., 0., 0. };
            double coord_2[3]{ 0., 0., 0. };
            line->getCoor1(coord_1);
            line->getCoor2(coord_2);

            // Get the mid-point for text label.
            double midPoint[3]{ (coord_2[0] + coord_1[0]) / 2.,
                (coord_2[1] + coord_1[1]) / 2.,
                (coord_2[2] + coord_1[2]) / 2. };

            // Get the ids of the model and node.
            _LineInfo info;
            line->getNode1(info._ModelId_1, info._NodeId_1);
            line->getNode2(info._ModelId_2, info._NodeId_2);

            // Store the ids.
            m_lastLinesInfo.push_back(info);

            // Add points and cells.
            addVertexCell(m_ugridStart, m_pointsStart, coord_1);
            addVertexCell(m_ugridEnd, m_pointsEnd, coord_2);

            // Add a line cell to grid data.
            //@{
            int id_1 = m_pointsLine->InsertNextPoint(coord_1);
            int id_2 = m_pointsLine->InsertNextPoint(coord_2);

            vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
            cell->InsertNextId(id_1);
            cell->InsertNextId(id_2);
            m_ugridLine->InsertNextCell(VTKCellType::VTK_LINE, cell);
            //@}

            // Add text grid data.
            m_pointsLabel->InsertNextPoint(midPoint);
            m_textArray->InsertNextValue(QStringToCharA(connTypeName));
        }

        // Save the set id.
        m_setId = connSet->getDataObjectID();

        // Save the type name.
        m_typeName = connTypeName;

        // Generate the csys graph objects.
        generateCsys();

        return true;
    }

    void FITKGraphObjectConnectorAssignment::generateCsys()
    {
        // Generate the coordinate graph.
        Interface::FITKAbaConnectorAssignment* connector = dynamic_cast<Interface::FITKAbaConnectorAssignment*>(_dataObj);
        if (!connector)
        {
            return;
        }

        int csysId_1 = connector->getCsysId1();
        int csysId_2 = connector->getCsysId2();

        // Get the coordinate object 1.
        Interface::FITKCoordinateSystem* coord_1 = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKCoordinateSystem>(csysId_1);
        if (coord_1)
        {
            m_coordGraphObj_1->setCoodinateSystem(coord_1);
            m_coordGraphObj_1->update(true);

            // Save the id.
            m_csysId_1 = csysId_1;
        }

        // Get the coordinate object 2.
        Interface::FITKCoordinateSystem* coord_2 = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKCoordinateSystem>(csysId_2);
        if (coord_2)
        {
            m_coordGraphObj_2->setCoodinateSystem(coord_2);
            m_coordGraphObj_2->update(true);

            // Save the id.
            m_csysId_2 = csysId_2;
        }
    }

    void FITKGraphObjectConnectorAssignment::generateGraph()
    {
        // Create actors only.
        initActors();

        // Shape mapper for start points.
        //@{
        // Show points.
        m_fActorStart->GetProperty()->SetRepresentation(0);
        m_fActorStart->GetProperty()->SetPointSize(m_glyphSize * 0.8);

        // Get the start points' color.
        double colorStart3[3]{ 0., 0., 0. };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_connStartPtColor, colorStart3);
        m_fActorStart->GetProperty()->SetColor(colorStart3);

        m_fActorStart->setInputDataObject(m_ugridStart);
        //@}

        // Shape mapper for end points.
        //@{
        vtkSmartPointer<FITKPolyPlacementMapper> mapperEnd = vtkSmartPointer<FITKPolyPlacementMapper>::New();
        mapperEnd->UseDepthBufferOff();

        // Set input connecton of label hierarchy and strategy.
        mapperEnd->SetInputConnection(m_labelHieEnd->GetOutputPort());
        mapperEnd->SetRenderStrategy(m_strategyEnd);
        mapperEnd->SetIteratorType(vtkLabelHierarchy::FULL_SORT);

        // Show all labels
        mapperEnd->SetPlaceAllLabels(true);
        mapperEnd->SetMaximumLabelFraction(1.);

        m_fActorEnd->SetMapper(mapperEnd);
        //@}

        // Text mapper for label(s).
        //@{
        vtkSmartPointer<vtkLabelPlacementMapper> mapperText = vtkSmartPointer<vtkLabelPlacementMapper>::New();
        mapperText->UseDepthBufferOff();
        mapperText->SetShapeToNone();
        mapperText->SetStyleToOutline();
        mapperText->SetOutputTraversedBounds(true);
        mapperText->UseUnicodeStringsOff();

        vtkSmartPointer<vtkFreeTypeLabelRenderStrategy> strategyText = vtkSmartPointer<vtkFreeTypeLabelRenderStrategy>::New();

        // Set input connecton of label hierarchy and strategy.
        mapperText->SetInputConnection(m_labelHieText->GetOutputPort());
        mapperText->SetRenderStrategy(strategyText);

        // Show all labels
        mapperText->SetPlaceAllLabels(true);
        mapperText->SetMaximumLabelFraction(1.);

        mapperText->SetIteratorType(vtkLabelHierarchy::FULL_SORT);
        mapperText->Update();

        m_fActorLabel->SetMapper(mapperText);
        //@}

        // Initialize the line actor's input.
        m_fActorLine->setInputDataObject(m_ugridLine);
    }

    void FITKGraphObjectConnectorAssignment::clearData()
    {
        // Clear the set id.
        m_setId = -1;

        // Clear the model info.
        m_lastLinesInfo.clear();

        // Clear the vtk data.
        resetVtkObj(m_pointsStart);
        resetVtkObj(m_ugridStart);

        resetVtkObj(m_pointsEnd);
        resetVtkObj(m_ugridEnd);

        resetVtkObj(m_pointsLine);
        resetVtkObj(m_ugridLine);

        resetVtkObj(m_pointsStart);
        resetVtkObj(m_ugridStart);
        resetVtkObj(m_ugridStart);

        resetVtkObj(m_pointsLabel);
        resetVtkObj(m_textArray);

        // Clear the csys data.
        clearCsysData();
    }

    void FITKGraphObjectConnectorAssignment::clearCsysData()
    {
        // Clear the coordinate objects.
        //@{
        if (m_coordGraphObj_1)
        {
            m_coordGraphObj_1->clear();
        }

        if (m_coordGraphObj_2)
        {
            m_coordGraphObj_2->clear();
        }
        //@}

        // Clear the csys ids.
        m_csysId_1 = -1;
        m_csysId_2 = -1;
    }

    void FITKGraphObjectConnectorAssignment::addVertexCell(vtkUnstructuredGrid* ugrid, vtkPoints* points, double* pt)
    {
        if (!ugrid || !points || !pt)
        {
            return;
        }

        // Add point.
        int ptId = points->InsertNextPoint(pt);

        // Add cell.( smart pointer )
        vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
        cell->InsertNextId(ptId);
        ugrid->InsertNextCell(VTKCellType::VTK_VERTEX, cell);
    }

    void FITKGraphObjectConnectorAssignment::simplified(bool enabled)
    {
        if (m_graphSimplified)
        {
            bool dataVisible = getDataVisibility();

            // Change the data visibility while changing the camera.
            if (dataVisible)
            {
                if (m_fActorStart)
                {
                    m_fActorStart->SetVisibility(!enabled);
                }

                if (m_fActorEnd)
                {
                    m_fActorEnd->SetVisibility(!enabled);
                }

                if (m_fActorLine)
                {
                    m_fActorLine->SetVisibility(!enabled);
                }

                if (m_fActorLabel)
                {
                    m_fActorLabel->SetVisibility(!enabled);
                }
            }
        }
        else
        {
            // Disabled or enable the visible points while rotating the camera.
            //@{
            // Check if the connector is highlighting.
            enableVisiblePoints(!enabled && !isHighlighting());
            //@}
        }

        // For the coordinates.
        if (m_coordGraphObj_1)
        {
            m_coordGraphObj_1->simplified(enabled);
        }

        if (m_coordGraphObj_2)
        {
            m_coordGraphObj_2->simplified(enabled);
        }
    }

    void FITKGraphObjectConnectorAssignment::enableVisiblePoints(bool enabled)
    {
        // The end points.
        if (m_labelHieEnd && m_visiblePtEnd)
        {
            m_labelHieEnd->RemoveAllInputConnections(0);
            m_labelHieEnd->RemoveAllInputs();

            if (enabled)
            {
                m_labelHieEnd->SetInputConnection(m_visiblePtEnd->GetOutputPort());
            }
            else
            {
                m_labelHieEnd->SetInputData(m_visiblePtEnd->GetOutput());
            }
        }

        // The label text.
        if (m_labelHieText && m_visiblePtText)
        {
            m_labelHieText->RemoveAllInputConnections(0);
            m_labelHieText->RemoveAllInputs();

            if (enabled)
            {
                m_labelHieText->SetInputConnection(m_visiblePtText->GetOutputPort());
            }
            else
            {
                m_labelHieText->SetInputData(m_visiblePtText->GetOutput());
            }
        }
    }
}   // namespace Exchange